package com.gupao.javavip.gof.singleton;

import java.util.concurrent.CountDownLatch;

public class SingletonFactory {
    private static CountDownLatch LATCH = null;

    public static CountDownLatch getLatch() {
        return LATCH;
    }

    private static Runnable buildSingletonTread(SingletonWay singletonWay) {
        switch (singletonWay) {
            case HUNGRY:
                return buildRunnable(HungrySingleton.class);
            case LAZY_UNSAFE:
                return buildRunnable(LazySingletonUnsafe.class);
            case LAZY_SAFE_METHOD:
                return buildRunnable(LazySingletonSafeMethod.class);
            case LAZY_SAFE_METHOD_CODE:
                return buildRunnable(LazySingletonSafeMethodCode.class);
            case LAZY_SAFE_INNER_CLASS:
                return buildRunnable(LazySingletonSafeInnerClass.class);
            case REGISTER_ENUM:
                return buildRunnable(RegisterEnumSingleton.class);
            case REGISTER_CONTAINER:
                return buildRunnable(RegisterContainerSingleton.class, String.class, "com.gupao.javavip.gof.singleton.TestPojo");
            case THREAD_LOCAL:
                return buildRunnable(ThreadLocalSingleton.class);
        }

        throw new IllegalArgumentException("错误的单例模式");
    }

    private static Runnable buildRunnable(Class clzz) {
        return buildRunnable(clzz, null, null);
    }

    private static Runnable buildRunnable(Class clzz, Class getInstanceParameterTypes, Object getInstanceParameter) {
        return new Runnable() {
            @Override
            public void run() {
                try {
                    Object obj = null;
                    if (getInstanceParameterTypes == null && getInstanceParameter == null) {
                        obj = clzz.getDeclaredMethod("getInstance").invoke(null);
                    } else {
                        obj = clzz.getDeclaredMethod("getInstance", getInstanceParameterTypes).invoke(null, getInstanceParameter);
                    }
                    System.out.println("[threadName]:" + Thread.currentThread().getName() + ";[className]:" + clzz.getSimpleName() + ";[instance]:" + obj);

                    LATCH.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }

    public static Thread[] build(SingletonWay singletonWay, int threadCount) {
        if (LATCH == null) {
            LATCH = new CountDownLatch(threadCount);
        } else {
            Integer count = Math.toIntExact(LATCH.getCount() + threadCount);
            LATCH = new CountDownLatch(count);
        }

        Thread[] threads = new Thread[threadCount];

        for (int i = 0; i < threadCount; i++) {
            Runnable runnable = buildSingletonTread(singletonWay);
            Thread thread = new Thread(runnable);
            threads[i] = thread;
        }

        return threads;
    }

    public static Thread build(SingletonWay singletonWay) {
        Thread[] threads = build(singletonWay, 1);
        return threads[0];
    }
}
